package uhasselt.ontologyplugin;

import java.net.*;
import java.util.HashMap;

import net.sf.saxon.s9api.XdmNode;
import java.util.Map;
import java.io.*;

public class UrlBasedReader extends OntologyReader 
{
	// the original server (e.g. server.com/#1) used to search in a thesaurus
	String _searchServer;
	// the original server (e.g. server.com/#1) used to get relations in a thesaurus (broader, ...)
	String _relationsServer;
	// the original server used to get a single concept (e.g. TRKN in jita)
	String _oneconceptServer;
	// the original server used to get top concepts for a thesaurus
	String _topconceptsServer;
	// NOTE: we could also use one server, but then we would have to reread the properties file again for every query
	// server with parameters filled in (e.g. server.com/keyword) (can be search or relations)
	// this string is ready to be passed to the server to perform the query
	String _serverQuery;
	// name of the thesaurus (e.g. agrovoc), we need this to query the config file ^
	String _thesaurus;
	// property reader to query the config file
	PropertyReader _reader;
		
	private static final String SEARCH_URL = "searchurl";
	private static final String RELATIONS_URL = "relationsurl";
	private static final String RELATION_SETTINGS = "relationsettings";
	private static final String ONECONCEPT_URL = "oneconcept";
	private static final String TOPCONCEPTS_URL = "topconcepts";

	public UrlBasedReader()
	{
		_searchServer = null;
		_relationsServer = null;
		_serverQuery = null;
		_thesaurus = null;
		_reader = new PropertyReader();
	}

	public void setSearchServer(String server)
	{
		_searchServer = server;
	}

	public String getServer()
	{
		return _searchServer;
	}
	
	public void setRelationsServer(String server)
	{
		_relationsServer = server;		
	}
	
	public String getRelationsServer()
	{
		return _relationsServer;
	}

	
	/**
	 * Creates the hashmap that is passed to substituteParam
	 * Takes strings and matches the first string with 1, the second with 2, ...
	 * @param strings Strings to be replaced with parameters
	 * @return HashMap that looks like (1->string[0], 2->string[1], ...)
	 */
	private HashMap<Integer, String> createMap(String... strings)
	{
		HashMap<Integer, String> ret = new HashMap<Integer, String>();
		int i = 1;
		for(String element : strings) {
            ret.put(i, element);
            i++;
		}
		return ret;
	}
	/**
	 * This function is used to preparte the _serverQuery member variable.
	 * Substitutes parameters with specific values in a server url.
	 * Example: a server url might look like http://www.destin-informatique.com/scheme/concept.svc/c?q=#1
	 * When a search query is to be executed, this function will substitute #1 with the keyword
	 * @param server A reference to the server where we want to substitute the parameter
	 * @param paramList Map that maps a parameter on the key to replace it with. (e.g. 1 -> "Word" means that we should replace #1 with "Word")
	 */
	private void substituteParam(String server, HashMap<Integer, String> paramList)
	{
		_serverQuery = server;
		for (Map.Entry<Integer, String> entry : paramList.entrySet()) {
			Integer param = entry.getKey();
			String replaceValue = entry.getValue();
			// convert param to #param
			String paramstr = "#" + param;
			_serverQuery = _serverQuery.replace(paramstr, replaceValue);
		}
	}

	/**
	 * Get the content of a webpage.
	 * @throws IOException
	 */
	private String httpget(String lang) throws IOException
	{
		String ret = new String();
		URL servQ = new URL(_serverQuery);
		URLConnection yc = servQ.openConnection();
		yc.addRequestProperty("Accept-Language",lang +";q=0.8");
		BufferedReader in = new BufferedReader(
				new InputStreamReader(
						yc.getInputStream()));
		String inputLine;

		while ((inputLine = in.readLine()) != null) 
			ret += inputLine + "\n";
		in.close();

		return ret;
	}

	@Override
	public XdmNode search(String searchTerm, SearchMode mode, String lang) 
	{
		// substitute searchTerm with #1 in the _searchServer url
		// createMap creates the map (1->searchTerm), substituteParam replaces #1 with searchTerm in _searchServer
		substituteParam(_searchServer, createMap(searchTerm));
		String result = null;
		// our server query is now ready, do an HTTP request
		try {
			result = httpget(lang);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return _transformer.transform(result);
	}

	/**
	 * Converts a RelationName to the appropriate String, defined in relationSettings.properties
	 * @param relName The RelationName that has to be converted to a String
	 * @param pathToConfig Path to relationSettings.properties
	 * @return The resulting RelationName converted to a String
	 */
	private String relationNameToString(RelationName relName)
	{
		String q = _thesaurus + "." + RELATION_SETTINGS + "." + relName.getText();
		return _reader.getValue(q);
	}

	@Override
	public XdmNode getRelations(String uri, RelationName relName,String lang) 
	{
		// substitute the first parameter with the uri and the second parameter with the relation name
		// createMap creates the map (1->uri, 2->relName), substituteParam replaces #1 with uri and #2 with relName
		substituteParam(_relationsServer, createMap(uri, relationNameToString(relName)));
		String result = null;
		// our server query is now ready, do an HTTP request
		try {
			result = httpget(lang);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return _transformer.transform(result);
	}

	@Override
	public XdmNode getTopLevelTerms(String lang) 
	{
		substituteParam(_topconceptsServer, createMap());
		String result = null;
		// our server query is now ready, do an HTTP request
		try {
			result = httpget(lang);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return _transformer.transform(result);
	}

	@Override
	public XdmNode getConcept(String uri,String lang) 
	{
		substituteParam(_oneconceptServer, createMap(uri));
		String result = null;
		// our server query is now ready, do an HTTP request
		try {
			result = httpget(lang);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return addRequiredRelations(_transformer.transform(result),uri,lang);
	}
	
	/**
	 * This function should be called right after its construction!
	 */
	public void initialise(PropertyReader reader, String thesaurus)
	{
		_reader = reader;
		_thesaurus = thesaurus;
		// determine the search url (e.g. agrovoc.searchurl)
		String searchurl = _thesaurus + "." + SEARCH_URL;
		_searchServer = _reader.getValue(searchurl);
		// determine the relations url (e.g. agrovoc.relationsurl)
		String relationsurl = _thesaurus + "." + RELATIONS_URL;
		_relationsServer = _reader.getValue(relationsurl);
		// determine the 'one concept' url (e.g. agrovoc.oneconcept)
		String oneconcepturl = _thesaurus + "." + ONECONCEPT_URL;
		_oneconceptServer = _reader.getValue(oneconcepturl);
		// determine the top concepts url (e.g. agrovoc.topconcepts)
		String topconceptsurl = _thesaurus + "." + TOPCONCEPTS_URL;
		_topconceptsServer = _reader.getValue(topconceptsurl);
		String transformer = _reader.getValue(_thesaurus + ".transformer");
		initRequiredRelations(reader,thesaurus);
		try {
			Class transClass = null;
			transClass = Class.forName(transformer);
			_transformer = (ToSkosTransformer) transClass.newInstance();
			_transformer.initialise(reader,thesaurus);
		} catch (ClassNotFoundException e) {
				e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

}
